package account.service;

import account.common.MobilePhoneNumber;
import account.common.RealName;
import account.pojo.QStudentAccount;
import account.pojo.StudentAccount;
import account.repository.StudentAccountRepository;
import account.service.template.StudentAccountTemplate;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.querydsl.jpa.impl.JPAUpdateClause;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import javax.validation.ValidationException;
import java.time.LocalDate;
import java.util.Optional;

@Transactional(rollbackOn = { RuntimeException.class })
@Service
public class StudentAccountServiceImpl implements StudentAccountService {

    private final StudentAccountRepository repo;

    private final JPAQueryFactory jpaQueryFactory;

    public StudentAccountServiceImpl(StudentAccountRepository repo, JPAQueryFactory jpaQueryFactory) {
        this.repo = repo;
        this.jpaQueryFactory = jpaQueryFactory;
    }

    @Override
    public StudentAccount createAccount(StudentAccount uncheckedInput) throws ValidationException {
        RealName name = RealName.fromUnsafeText(uncheckedInput.getRealName());
        LocalDate dob = uncheckedInput.getDob();
        MobilePhoneNumber phone = MobilePhoneNumber.fromUncheckedInput(uncheckedInput.getPrimaryMobilePhoneNumber());
        StudentAccount stuAccount = new StudentAccount();
        stuAccount.setId(null);
        stuAccount.setRealName(name.asPlainText());
        stuAccount.setDob(dob);
        stuAccount.setPrimaryMobilePhoneNumber(phone.asPlainText());
        return repo.save(stuAccount);
    }

    @Override
    public StudentAccount createAccount(StudentAccountTemplate template) {
        StudentAccount stuAccount = new StudentAccount();
        stuAccount.setId(null);
        stuAccount.setRealName(template.getRealName());
        stuAccount.setDob(template.getDob());
        stuAccount.setPrimaryMobilePhoneNumber(template.getPrimaryMobilePhoneNumber());
        return repo.save(stuAccount);
    }

    @Override
    public StudentAccount overwriteAccountById(Long id, StudentAccountTemplate template) {
        StudentAccount stuAccount = new StudentAccount();
        stuAccount.setId(id);
        stuAccount.setRealName(template.getRealName());
        stuAccount.setDob(template.getDob());
        stuAccount.setPrimaryMobilePhoneNumber(template.getPrimaryMobilePhoneNumber());
        return repo.save(stuAccount);
    }

    @Override
    public Optional<StudentAccount> findById(Long id) {
        return repo.findById(id);
    }

    @Override
    public Page<StudentAccount> findAll(Pageable pageable) {
        return repo.findAll(pageable);
    }

    @Override
    public long update(StudentAccount uncheckedInput) throws ValidationException {
        Long id = uncheckedInput.getId();
        QStudentAccount record = QStudentAccount.studentAccount;
        JPAUpdateClause clause = jpaQueryFactory.update(record).where(record.id.eq(id));

        String unsafeText = uncheckedInput.getRealName();
        if (null != unsafeText) {
            RealName name = RealName.fromUnsafeText(unsafeText);
            clause.set(record.realName, name.asPlainText());
        }

        LocalDate uncheckedInputDob = uncheckedInput.getDob();
        if (null != uncheckedInputDob) {
            clause.set(record.dob, uncheckedInputDob);
        }

        String uncheckedPhoneNum = uncheckedInput.getPrimaryMobilePhoneNumber();
        if (null != uncheckedPhoneNum) {
            MobilePhoneNumber phoneNum = MobilePhoneNumber.fromUncheckedInput(uncheckedPhoneNum);
            clause.set(record.primaryMobilePhoneNumber, phoneNum.asPlainText());
        }

        return clause.execute();
    }

    @Override
    public Boolean existsById(Long id) {
        return repo.existsById(id);
    }
}
